package com.resource.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.resource.configuration.http.HttpClientUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.resource.constant.OfficeApiConstants;
import com.resource.converter.ContractConverter;
import com.resource.dto.*;
import com.resource.query.ContractQuery;
import com.resource.query.ContractValidateQuery;
import com.resource.request.ContractArchiveRequest;
import com.resource.request.ContractSaveRequest;
import com.resource.response.ContractDetailResponse;
import com.resource.response.ContractPageItemResponse;
import com.resource.response.OfficePageWrapper;
import com.resource.response.OfficeResponse;
import com.resource.service.ContractService;
import com.resource.utils.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 调用泛微接口进行合同的增删改查
 *
 * @author jianghao.zhang
 */
@Slf4j
@Service
public class ContractServiceImpl implements ContractService {

	private static final String COMMA = ",";

	@Resource
	private ContractConverter contractConverter;

	@Value("${office.api.url}")
	private String apiUrl;

	@Value("${office.app.user}")
	private String user;
	@Resource
	private RestTemplate restTemplate;

	/**
	 * [分页查询] 合同列表
	 *
	 * @param query
	 *            查询参数
	 * @return 分页结果
	 */
	@Override
	public OfficePageWrapper<ContractPageItemResponse> queryPage(ContractQuery query) throws ServiceException {
		// 准备查询参数
		Map<String, List<String>> condition;
		Map<String, Object> params = new HashMap<>(4);
		if (CollectionUtil.isNotEmpty(query.getIdList())) {
			params.put("search", prepareSearchStrWhenQueryByIds(query.getIdList()));
		} else {
			try {
				condition = SearchUtils.getQuery(query);
			} catch (Exception e) {
				throw new ServiceException("合同获取查询条件失败");
			}
			params.put("search", JSONUtil.toJsonStr(condition));
		}
		params.put("order_by", "{\"created_at\":\"desc\"}");

		// 拼接URL，设置请求头
		String url = String.format(OfficeApiConstants.CONTRACT_LIST_URL, apiUrl) + "?page=" + query.getPage()
				+ "&limit=" + query.getLimit() + "&search={search}&order_by={order_by}";
		HttpEntity<String> entity = HttpUtils.setHttpEntity(HttpMethod.GET, "parameters", user);

		// 执行http调用
		new OfficePageWrapper<>();
		OfficePageWrapper<ContractPageItemDto> page;
		log.info("【contract】queryPage request entity : {}, params : {}", JSONUtil.toJsonStr(entity),
				JSONUtil.toJsonStr(params));
		try {
			ResponseEntity<OfficeResponse<OfficePageWrapper<ContractPageItemDto>>> resp = HttpClientUtils.getClient()
					.exchange(url, HttpMethod.GET, entity,
							new ParameterizedTypeReference<OfficeResponse<OfficePageWrapper<ContractPageItemDto>>>() {
							}, params);
			log.info("【contract】queryPage response：{}", JSONUtil.toJsonStr(resp));

			page = resp.getBody().getData();
		} catch (Exception e) {
			log.error("查询合同分页失败，出现异常：", e.getCause());
			throw new ServiceException("查询合同分页失败，出现异常：", e.getCause());
		}

		// 组装返回结果
		OfficePageWrapper<ContractPageItemResponse> result = new OfficePageWrapper<>();
		List<ContractPageItemResponse> contractDetailDtoList = new ArrayList<>();
		List<ContractPageItemDto> list = page.getList();
		if (CollectionUtil.isNotEmpty(list)) {
			ContractPageItemResponse dto;
			for (ContractPageItemDto item : list) {
				dto = contractConverter.responseToPageDto(item);
				contractDetailDtoList.add(dto);
			}
		}

		result.setList(contractDetailDtoList);
		result.setTotal(page.getTotal());
		return result;
	}

	/**
	 * 当根据id列表查询合同时，准备search条件
	 *
	 * @param ids
	 *            id列表
	 * @return search条件字符串
	 */
	private String prepareSearchStrWhenQueryByIds(List<Integer> ids) {
		StringBuilder idsStrBuilder = new StringBuilder();
		if (CollectionUtil.isNotEmpty(ids)) {
			for (Integer id : ids) {
				idsStrBuilder.append(id).append(COMMA);
			}
		}
		String idsStr = idsStrBuilder.toString();
		if (idsStr.length() > 0 && idsStr.endsWith(COMMA)) {
			idsStr = idsStr.substring(0, idsStr.length() - 1);
		}

		return "{\"id\":[[" + idsStr + "],\"in\"]}";
	}

	/**
	 * [查询]单个合同，根据id
	 *
	 * @param id
	 *            id
	 * @return 合同详情
	 */
	@Override
	public ContractDetailResponse queryContractById(Integer id) throws ServiceException {
		ContractDetailDto data = queryContractDetailDtoById(id);
		List<Integer> childContracts = data.getChildContracts().stream().map(ChildContractDto::getId)
				.collect(Collectors.toList());
		ContractDetailResponse contractDetailResponse = contractConverter.responseToDto(data);
		contractDetailResponse.setChildContract(childContracts);
		return contractDetailResponse;
	}

	@Override
	public ContractDetailDto queryContractDetailDtoById(Integer id) {
		HttpEntity<String> entity = HttpUtils.setHttpEntity(HttpMethod.GET, "parameters", user);
		log.info("【contract】queryContractById id : {}", id);
		try {
			ResponseEntity<OfficeResponse> resp = HttpClientUtils.getClient().exchange(
					apiUrl + OfficeApiConstants.CONTRACT_DETAIL_URL + id, HttpMethod.GET, entity,
					new ParameterizedTypeReference<OfficeResponse>() {
					});
			log.info("【contract】queryContractById response：{}", JSONUtil.toJsonStr(resp));
			return BeanUtil.toBean(Objects.requireNonNull(resp.getBody()).getData(), ContractDetailDto.class);
		} catch (Exception e) {
			log.error("根据id查询合同失败，出现异常：", e.getCause());
			throw new ServiceException("根据id查询合同失败，出现异常：", e.getCause());
		}
	}

	/**
	 * [添加]合同
	 *
	 * @param request
	 *            请求参数
	 */
	@Override
	public void addContract(ContractSaveRequest request) throws ServiceException {
		ContractSaveDto saveDto = new ContractSaveDto();
		ContractSaveMainDto main = contractConverter.requestToAddDto(request);
		saveDto.setContract(main);
		HttpEntity<String> req = HttpUtils.setHttpEntity(HttpMethod.POST, JSONUtil.toJsonStr(saveDto), user);

		log.info("【contract】addContract request : {}", req);
		try {
			ResponseEntity<OfficeResponse<Object>> resp = HttpClientUtils.getClient().exchange(
					apiUrl + OfficeApiConstants.CONTRACT_ADD_URL, HttpMethod.POST, req,
					new ParameterizedTypeReference<OfficeResponse<Object>>() {
					});
			log.info("【contract】addContract response：{}", JSONUtil.toJsonStr(resp));

			if (!ObjectUtil.equal(resp.getStatusCode(), HttpStatus.OK) || resp.getBody() == null
					|| resp.getBody().getStatus() != OfficeApiConstants.SUCCESS) {
				throw new ServiceException("新增合同失败：" + JSONUtil.toJsonStr(resp.getBody()));
			}
		} catch (Exception e) {
			log.error("新增合同失败，出现异常：", e.getCause());
			throw new ServiceException("新增合同失败，出现异常：", e.getCause());
		}
	}

	/**
	 * [修改]合同
	 *
	 * @param request
	 *            请求参数
	 */
	@Override
	public void updateContract(ContractSaveRequest request) throws ServiceException {
		ContractSaveMainDto main = contractConverter.requestToAddDto(request);
		doUpdateContract(main, user);
	}

	private void doUpdateContract(ContractSaveMainDto saveMainDto, String userId) throws ServiceException {
		ContractSaveDto updateDto = new ContractSaveDto();
		updateDto.setContract(saveMainDto);
		HttpEntity<String> req = HttpUtils.setHttpEntity(HttpMethod.PUT, JSONUtil.toJsonStr(updateDto), userId);

		log.info("【contract】updateContract id : {}, params : {}", saveMainDto.getId(), req);
		try {
			ResponseEntity<OfficeResponse> resp = HttpClientUtils.getClient().exchange(
					apiUrl + OfficeApiConstants.CONTRACT_UPDATE_URL + saveMainDto.getId(), HttpMethod.PUT, req,
					OfficeResponse.class);
			log.info("【contract】updateContract response：{}", JSONUtil.toJsonStr(resp));

			if (!ObjectUtil.equal(resp.getStatusCode(), HttpStatus.OK) || resp.getBody() == null
					|| resp.getBody().getStatus() != OfficeApiConstants.SUCCESS) {
				throw new ServiceException("修改合同失败：" + JSONUtil.toJsonStr(resp.getBody()));
			}
		} catch (Exception e) {
			log.error("修改合同失败，出现异常：", e.getCause());
			throw new ServiceException("修改合同失败，出现异常：", e.getCause());
		}
	}

	/**
	 * [删除]合同
	 *
	 * @param id
	 *            id
	 */
	@Override
	public void deleteContract(Integer id) throws ServiceException {
		HttpEntity<String> req = HttpUtils.setHttpEntity(HttpMethod.PUT, OfficeApiConstants.IS_NULL, user);

		log.info("【contract】deleteContract id : {}", id);
		try {
			ResponseEntity<OfficeResponse<Object>> resp = HttpClientUtils.getClient().exchange(
					apiUrl + OfficeApiConstants.CONTRACT_DELETE_URL + id, HttpMethod.DELETE, req,
					new ParameterizedTypeReference<OfficeResponse<Object>>() {
					});
			log.info("【contract】deleteContract response：{}", JSONUtil.toJsonStr(resp));

			if (!ObjectUtil.equal(resp.getStatusCode(), HttpStatus.OK) || resp.getBody() == null
					|| resp.getBody().getStatus() != OfficeApiConstants.SUCCESS) {
				throw new ServiceException("删除合同失败：" + JSONUtil.toJsonStr(resp.getBody()));
			}
		} catch (Exception e) {
			log.error("删除合同失败，出现异常：", e.getCause());
			throw new ServiceException("删除合同失败，出现异常 : " + e.getCause());
		}
	}

	/**
	 * 校验合同编号是否重复
	 *
	 * @param query
	 *            校验参数
	 * @return true 是，false否
	 */
	@Override
	public String validateRepeatedNumber(ContractValidateQuery query) throws ServiceException {
		// 准备查询参数
		Map<String, Object> params = new HashMap<>(1);
		params.put("search", getQuery(query));

		// 拼接URL，设置请求头
		String url = String.format(OfficeApiConstants.CONTRACT_LIST_URL, apiUrl) + "?page=1&limit=10&search={search}";
		HttpEntity<String> entity = HttpUtils.setHttpEntity(HttpMethod.GET, "parameters", user);

		// 执行http调用
		List<ContractPageItemDto> list;
		log.info("【contract】validateRepeatedNumber request entity : {}, params : {}", JSONUtil.toJsonStr(entity),
				JSONUtil.toJsonStr(params));
		try {
			ResponseEntity<OfficeResponse<OfficePageWrapper<ContractPageItemDto>>> resp = HttpClientUtils.getClient()
					.exchange(url, HttpMethod.GET, entity,
							new ParameterizedTypeReference<OfficeResponse<OfficePageWrapper<ContractPageItemDto>>>() {
							}, params);
			log.info("【contract】validateRepeatedNumber response：{}", JSONUtil.toJsonStr(resp));

			list = resp.getBody().getData().getList();
		} catch (Exception e) {
			log.error("校验合同编号是否重复，出现异常：", e.getCause());
			throw new ServiceException("校验合同编号是否重复，出现异常：", e.getCause());
		}

		if (CollectionUtil.isNotEmpty(list)) {
			StringBuilder errorMsg = new StringBuilder();
			list.forEach(c -> {
				if (ObjectUtil.equal(c.getNumber(), query.getDATA_19())) {
					errorMsg.append("合同编号：【").append(query.getDATA_19()).append("】已存在；");
				}
			});
			return errorMsg.toString();
		} else {
			return "true";
		}
	}

	/**
	 * 拼接查询条件字符串
	 *
	 * @param query
	 *            原始查询参数
	 * @return 字符串
	 */
	private String getQuery(ContractValidateQuery query) {
		return "{\"number\":[\"" + query.getDATA_19() + "\",\"=\"]}";
	}

	/**
	 * 合同归档数据外发处理
	 *
	 * @param request
	 *            请求数据
	 */
	@Override
	public void updateContractArchive(ContractArchiveRequest request) {
		String userId = StrUtil.isEmpty(request.getDATA_115().get(0)) ? user : request.getDATA_115().get(0);

		ContractQuery query = new ContractQuery();
		query.setNumber(request.getDATA_19());
		query.setTitle(request.getDATA_20());
		OfficePageWrapper<ContractPageItemResponse> page = queryPage(query);
		if (page != null && CollectionUtil.isEmpty(page.getList())) {
			throw new ServiceException("合同归档数据外发处理，根据编号" + query.getNumber() + "和标题" + query.getTitle() + "未查询到合同");
		}

		Integer id = page.getList().get(0).getId();
		ContractDetailDto data = queryContractDetailDtoById(id);

		// 校验存在性
		if (ObjectUtil.isEmpty(data)) {
			throw new ServiceException("未找到id为" + id + "的合同");
		}

		ContractSaveMainDto saveMainDto = new ContractSaveMainDto();
		BeanUtil.copyProperties(data, saveMainDto);
		// 仅能修改 归档状态 用印状态 附件
		saveMainDto.setField_41(request.getDATA_116());
		saveMainDto.setField_42(request.getDATA_114());
		saveMainDto.setField_44(request.getDATA_118());
		saveMainDto.setStatus(1);

		try {
			doUpdateContract(saveMainDto, userId);
		} catch (Exception e) {
			log.error("合同归档外发处理失败，出现异常：", e.getCause());
			throw new ServiceException("合同归档外发处理失败，出现异常：", e.getCause());
		}
	}

	@Override
	public void updateContractBySend(ContractSaveDto dto) {
		String uri = apiUrl + OfficeApiConstants.CONTRACT_UPDATE_URL + dto.getContract().getId();
		HttpEntity<String> entity = HttpUtils.setHttpEntity(HttpMethod.PUT, JSONUtil.toJsonStr(dto), user);
		log.info("【updateContractBySend request】{}", JSONUtil.toJsonStr(dto));
		ResponseEntity<OfficeResponse> exchange = restTemplate.exchange(uri, HttpMethod.PUT, entity,
				OfficeResponse.class);
		log.info("【updateContractBySend response!】{}", JSONUtil.toJsonStr(exchange));
		ValidateUtils.checkResponse(exchange);
	}

	@Override
	public List<JSONObject> listContractInfo(Map<String, List<Object>> condition) {
		// 拼接URL，设置请求头
		Map<String, Object> params = new HashMap<>(4);
		params.put("search", JSONUtil.toJsonStr(condition));
		String url = String.format(OfficeApiConstants.CONTRACT_LIST_URL, apiUrl) + "?page=0" + "&search={search}";
		HttpEntity<String> entity = HttpUtils.setHttpEntity(HttpMethod.GET, "parameters", user);
		ResponseEntity<OfficeResponse> resp = HttpClientUtils.getClient().exchange(url, HttpMethod.GET, entity,
				OfficeResponse.class, params);
		log.info("【contract】list response：{}", JSONUtil.toJsonStr(resp));
		// 校验返回http请求返回信息
		OfficeResponse officeResponse = ValidateUtils.checkResponse(resp);
		PageInfo<JSONObject> pageInfo = Convert.convert(new TypeReference<PageInfo<JSONObject>>() {
		}, officeResponse.getData());
		return pageInfo.getList();
	}

	@Override
	public void importContract(ContractImportDto dto) {
		String url = apiUrl+"/"+OfficeApiConstants.CONTRACT_ADD_URL;
		// 创建请求头
		JSONObject jsonObject1 = JSONUtil.parseObj(dto);
		jsonObject1.remove("attachments");
		jsonObject1.remove("cellStyleMap");
		jsonObject1.remove("userIds");
		JSONObject jsonObject=new JSONObject();
		jsonObject.putOpt("contract",jsonObject1);
		HttpEntity<String> entity = HttpUtils.setHttpEntity(HttpMethod.POST, jsonObject.toString(), user);
		ResponseEntity<OfficeResponse> responseEntity = restTemplate.exchange(url, HttpMethod.POST, entity,
				OfficeResponse.class);
		log.info("【office】contract import add return：{}", JSONUtil.toJsonStr(responseEntity));
		// 校验返回http请求返回信息
		ValidateUtils.checkResponse(responseEntity);
	}
}
